package com.dc.commons.query;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

import javax.persistence.criteria.AbstractQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Subquery;

import org.apache.commons.lang3.StringUtils;

import com.dc.commons.enumer.Enumer;
import com.dc.commons.enumer.EnumerJson;
import com.dc.commons.helper.DateHelper;
import com.dc.commons.persistence.embeddable.Data;
import com.dc.commons.persistence.embeddable.Dict;
import com.dc.commons.persistence.embeddable.Member;
import com.dc.commons.persistence.embeddable.Organ;
import com.dc.commons.query.DynamicSpecifications.Group;
import com.google.common.collect.Lists;

/*******************************************************************************<P>
 * 文件名: QueryOperator.java <br>
 * 版本: 1.0<br>
 * 描述:<br>
 * 版权所有: <br>
 * <P>
 * 创建者: 王建栋 <br>
 * 创建日期: 2016年5月31日 下午3:29:22<br>
 * 修改者: <br>
 * 修改日期: <br>
 * 修改说明: <br>
 ******************************************************************************/
public enum QueryOperator implements EnumerJson,Expressioner{
	
	EQ("等于"){
		
		@Override
		public Predicate expression(Root<?> root,AbstractQuery<?> query,CriteriaBuilder builder, Expression<?> expression, SearchFilter searchFilter) {
			Object value=getValue(root, query, builder, expression, searchFilter);
			return builder.equal(expression, value);
		}
	},
	NEQ("不等于"){
		
		@Override
		public Predicate expression(Root<?> root,AbstractQuery<?> query,CriteriaBuilder builder, Expression<?> expression, SearchFilter searchFilter) {
			Object value=getValue(root, query, builder, expression, searchFilter);
			return builder.not(builder.equal(expression, value));
		}
	},
	LK("匹配"){
		
		@SuppressWarnings("unchecked")
		@Override
		public Predicate expression(Root<?> root,AbstractQuery<?> query,CriteriaBuilder builder, Expression<?> expression, SearchFilter searchFilter) {
			Object value=getValue(root, query, builder, expression, searchFilter);
			return builder.like((Expression<String>) expression, "%"+value.toString()+"%");
		}
	},
	
	NLK("不匹配"){
		
		@SuppressWarnings("unchecked")
		@Override
		public Predicate expression(Root<?> root,AbstractQuery<?> query,CriteriaBuilder builder, Expression<?> expression, SearchFilter searchFilter) {
			Object value=getValue(root, query, builder, expression, searchFilter);
			return builder.not(builder.like((Expression<String>) expression, "%"+value+"%"));
		}
	},
	GT("大于"){
		
		@SuppressWarnings({ "unchecked", "rawtypes" })
		@Override
		public Predicate expression(Root<?> root,AbstractQuery<?> query,CriteriaBuilder builder, Expression<?> expression, SearchFilter searchFilter) {
			Object value=getValue(root, query, builder, expression, searchFilter);
			return builder.greaterThan((Expression<? extends Comparable>)expression, (Comparable)value);
		}
	},
	LT("小于"){
		
		@SuppressWarnings({ "unchecked", "rawtypes" })
		@Override
		public Predicate expression(Root<?> root,AbstractQuery<?> query,CriteriaBuilder builder, Expression<?> expression, SearchFilter searchFilter) {
			Object value=getValue(root, query, builder, expression, searchFilter);
			return builder.lessThan((Expression<? extends Comparable>)expression, (Comparable)value);
		}
	},
	GE("大于等于"){
		
		@SuppressWarnings({ "unchecked", "rawtypes" })
		@Override
		public Predicate expression(Root<?> root,AbstractQuery<?> query,CriteriaBuilder builder, Expression<?> expression, SearchFilter searchFilter) {
			Object value=getValue(root, query, builder, expression, searchFilter);
			return builder.greaterThanOrEqualTo((Expression<? extends Comparable>)expression, (Comparable)value);
		}
	},
	LE("小于等于"){
		
		@SuppressWarnings({ "unchecked", "rawtypes" })
		@Override
		public Predicate expression(Root<?> root,AbstractQuery<?> query,CriteriaBuilder builder, Expression<?> expression, SearchFilter searchFilter) {
			Object value=getValue(root, query, builder, expression, searchFilter);
			return builder.lessThanOrEqualTo((Expression<? extends Comparable>)expression, (Comparable)value);
		}
	},
	IN("包含"){
		
		/**
		 *  IN 的时候需要将数据用逗号隔开
		 */
		Object getValue(Root<?> root,AbstractQuery<?> query,CriteriaBuilder builder, Expression<?> expression, SearchFilter searchFilter){
			String[] values=searchFilter.getValue().toString().trim().split(",");
			List<Object> list=Lists.newArrayList();
			for(String value:values){
				Object o=getSimpleValue(root, query, builder, expression, value);
				list.add(o);
			}
			return list;
		}
		@SuppressWarnings({ "unchecked", "rawtypes" })
		@Override
		public Predicate expression(Root<?> root,AbstractQuery<?> query,CriteriaBuilder builder, Expression<?> expression, SearchFilter searchFilter) {
			Object values=getValue(root, query, builder, expression, searchFilter);
			Expression expression2=expression;
			return builder.in(expression2).value(values);
		}
	},
	NIN("不包含"){
		
		/**
		 *  NIN 的时候需要将数据用逗号隔开
		 */
		Object getValue(Root<?> root,AbstractQuery<?> query,CriteriaBuilder builder, Expression<?> expression, SearchFilter searchFilter){
			String[] values=searchFilter.getValue().toString().trim().split(",");
			List<Object> list=Lists.newArrayList();
			for(String value:values){
				Object o=getSimpleValue(root, query, builder, expression, value);
				list.add(o);
			}
			return list;
		}
		
		@Override
		@SuppressWarnings({ "unchecked", "rawtypes" })
		public Predicate expression(Root<?> root,AbstractQuery<?> query,CriteriaBuilder builder, Expression<?> expression, SearchFilter searchFilter) {
			Expression expression2=expression;
			Object values=getValue(root, query, builder, expression, searchFilter);
			return builder.not(builder.in(expression2).value(values));
		}
	},
	ISNULL("为空"){
		
		@Override
		public Predicate expression(Root<?> root,AbstractQuery<?> query,CriteriaBuilder builder, Expression<?> expression, SearchFilter searchFilter) {
			return builder.isNull(expression);
		}
	},
	NOTNULL("不为空"){
		
		@Override
		public Predicate expression(Root<?> root,AbstractQuery<?> query,CriteriaBuilder builder, Expression<?> expression, SearchFilter searchFilter) {
			return builder.isNotNull(expression);
		}
	},
	EXISTS("包含-子查询"){
		
		/**
		 * 在子查询部分再做处理
		 */
		Object getValue(Root<?> root,AbstractQuery<?> query,CriteriaBuilder builder, Expression<?> expression, SearchFilter searchFilter){
			return searchFilter.getValue();
		}
		
		@Override
		public Predicate expression(Root<?> root,AbstractQuery<?> query,CriteriaBuilder builder, Expression<?> expression, SearchFilter searchFilter) {
			Subquery<?> subQuery=subquery(root, query, builder, expression, searchFilter);
			return builder.exists(subQuery);
		}
	},
	NEXISTS("不包含-子查询"){
		
		/**
		 * 在子查询部分再做处理
		 */
		Object getValue(Root<?> root,AbstractQuery<?> query,CriteriaBuilder builder, Expression<?> expression, SearchFilter searchFilter){
			return searchFilter.getValue();
		}
		@Override
		public Predicate expression(Root<?> root,AbstractQuery<?> query,CriteriaBuilder builder, Expression<?> expression, SearchFilter searchFilter) {
			Subquery<?> subQuery=subquery(root, query, builder, expression, searchFilter);
			return builder.not(builder.exists(subQuery));
		}
	},
	//"search_OR_EQ_dataStatus|EQ_userName":["VALID","admin"]
	OR("或分组标记"){
		
		@Override
		@SuppressWarnings({ "unchecked", "rawtypes" })
		public Predicate expression(Root<?> root,AbstractQuery<?> query,CriteriaBuilder builder, Expression<?> expression, SearchFilter searchFilter) {
			List<SearchFilter> subSearch=(List<SearchFilter>)searchFilter.getValue();
				Class clazz=root.getJavaType();
				CriteriaQuery<?> query2=(CriteriaQuery)query;
				Predicate predicate=DynamicSpecifications
						.buildDcQuery(subSearch, Group.OR, clazz)
						.toPredicate(root, query2, builder);
				
			return builder.and(predicate);
		}
	};
	
	
	
	QueryOperator(String name) {
		this.name=name;
	}
	private String name;

	@Override
	public Enumer getEnumber() {
		return Enumer.toEnumber(this.name(), name);
	}
	
	/**
	 * 构建子查询
	 * 例："search_com.dc.modules.exam.taskuser.domain.ExamTaskUser.user_EXISTS":{"taskId_EQ:1"}
	 *   searchName:String:com.dc.modules.exam.taskuser.domain.ExamTaskUser.user
	 *   QueryOperator:EXISTS
	 *   value:Map:{SearchFilters}
	 * @param root
	 * @param query
	 * @param builder
	 * @param expression
	 * @param searchFilter
	 * @return subQuery 子查询
	 */
	@SuppressWarnings("unchecked")
	Subquery<?> subquery(Root<?> root,AbstractQuery<?> query,CriteriaBuilder builder, Expression<?> expression, SearchFilter searchFilter){
		String searchName=searchFilter.getSearchName();
		String joinField=searchName.substring(searchName.lastIndexOf(".")+1);
		Class<?> joinClass=null;
		
		//FIXME 用如下方式可以获取到 对应的类全名称。但是这里面没有注入相对应的东西，
		/**
		 * 	
		 * for(String key:entityManagerFactoryInfo.getPersistenceUnitInfo().getManagedClassNames()){
			System.out.println(key);
			
		}
		 */
		
		try {
			joinClass=Class.forName(searchName.substring(0, searchName.lastIndexOf(".")));
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
			throw new RuntimeException(searchName.substring(0, searchName.lastIndexOf("."))+"类不存在!");
		}
		
		Subquery<?> subQuery=query.subquery(joinClass);
		@SuppressWarnings("rawtypes")
		Root taskRoot=subQuery.from(joinClass );
		//Root taskRoot=subQuery.correlate(root);
		Join<?, ?> join=taskRoot.join(joinField);
		List<Predicate> preList=Lists.newArrayList(builder.equal(join, root));
		
		subQuery.select(taskRoot);
		if(searchFilter.getValue() instanceof List){
			List<SearchFilter> subSearch=(List<SearchFilter>)searchFilter.getValue();
			for(SearchFilter subFilter:subSearch){
				// 处理 子查询中有或的情况
				String[] split=StringUtils.split(subFilter.getSearchName(),"|");
				if(split.length!=1){
					List<Predicate> list=Lists.newArrayList();
					for(String name:split){
						Expression<?> subExpression=getExpresion(taskRoot,name);
						list.add(searchFilter.getQueryOperator().expression(root, query, builder, subExpression, searchFilter));
					}
					preList.add(builder.or(list.toArray(new Predicate[list.size()])));
				}else{
					Path<?> subExpression=getExpresion(taskRoot,subFilter.getSearchName());
					parse(taskRoot, builder, subQuery, subExpression, preList,subFilter);
				}
				
			}
			
			subQuery.where(preList.toArray(new Predicate[preList.size()]));
		}
		
		return subQuery;
	}
	
	
	/**
	 * 获取查询的真实数据
	 * @param root
	 * @param query
	 * @param builder
	 * @param expression
	 * @param searchFilter
	 * @return Object 查询值
	 */
	Object getValue(Root<?> root,AbstractQuery<?> query,CriteriaBuilder builder, Expression<?> expression, SearchFilter searchFilter){
		String value=searchFilter.getValue().toString().trim();
		return getSimpleValue(root, query, builder, expression, value);
	}
	
	/**
	 * 获取查询的真实数据 不需要分隔的单独数据
	 * @param root
	 * @param query
	 * @param builder
	 * @param expression
	 * @param searchFilter
	 * @return Object 查询值
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	Object getSimpleValue(Root<?> root,AbstractQuery<?> query,CriteriaBuilder builder, Expression<?> expression, String value){
		Class clazz=expression.getJavaType();
		if(clazz.isAssignableFrom(String.class)){
			return value;
		}
		if(clazz.isEnum()){
			return Enum.valueOf(clazz, value);
		}
		if(clazz.isAssignableFrom(Dict.class)){
			return Dict.valueOf(value);
		}
		if(clazz.isAssignableFrom(Date.class)){
			return DateHelper.parseDate(value);
		}
		if(clazz.isAssignableFrom(Member.class)){
			return Member.valueOf(value);
		}
		if(clazz.isAssignableFrom(Data.class)){
			return Data.valueOf(value);
		}
		if(clazz.isAssignableFrom(Organ.class)){
			return Organ.valueOf(value);
		}
		
		if(clazz.isAssignableFrom(Long.class)){
			return Long.valueOf(value);
		}
		if(clazz.isAssignableFrom(Integer.class)){
			return Integer.valueOf(value);
		}
		if(clazz.isAssignableFrom(Short.class)){
			return Short.valueOf(value);
		}
		if(clazz.isAssignableFrom(Double.class)){
			return Double.valueOf(value);
		}
		if(clazz.isAssignableFrom(Float.class)){
			return Float.valueOf(value);
		}
		if(clazz.isAssignableFrom(BigDecimal.class)){
			return new BigDecimal(value);
		}
		
		return value;
	}
	
	/**
	 * 解析 单个字段的数据
	 * @param root
	 * @param builder
	 * @param query
	 * @param expression
	 * @param predicates
	 * @param filter
	 */
	void parse(Root<?> root,CriteriaBuilder builder,AbstractQuery<?> query,Expression<?> expression,List<Predicate> predicates,SearchFilter searchFilter){
		predicates.add(searchFilter.getQueryOperator().expression(root, query, builder, expression, searchFilter));
	}
	
	public Path<?> getExpresion(Root<?>root,String name){
		String[] names=StringUtils.split(name,".");
		Path<?> expression=root.get(names[0]);
		for(int i=1;i<names.length;i++){
			expression=expression.get(names[i]);
		}
		return expression;
	}

}
